#include "mousedevice.h"

#include <stdio.h>

#ifndef VK_ALT
    #define VK_ALT                      164
#endif

MouseDevice::MouseDevice()
{
    delay = 50; // 50ms default
    vMouseX = 0;
    vMouseY = 0;
    attachedHwnd = NULL;
	wineMode = false;
}

HWND MouseDevice::getAttachedHwnd()
{
    return attachedHwnd;
}

void MouseDevice::setAttachedInput(HWND hwnd)
{
    attachedHwnd = hwnd;
}

void MouseDevice::setDelay(unsigned int _delay)
{
    delay = _delay;
}

void MouseDevice::move(int _dx, int _dy)
{
    if( attachedHwnd ) {
        vMouseX += _dx; vMouseY += _dy; }
    else {
        INPUT inp;
        inp.type = INPUT_MOUSE;
        inp.mi.dx = _dx;
        inp.mi.dy = _dy;
        inp.mi.dwFlags = MOUSEEVENTF_MOVE;
        inp.mi.time = 0;
        SendInput(1, &inp, sizeof(INPUT));
    }

}

void MouseDevice::set(int _dx, int _dy)
{
    if( attachedHwnd ) {
        POINT tmppt; tmppt.x = _dx; tmppt.y = _dy;
        ScreenToClient(attachedHwnd, &tmppt);
        vMouseX = tmppt.x; vMouseY = tmppt.y;
    } else {
        double fScreenWidth = ::GetSystemMetrics(SM_CXSCREEN)-1;
        double fScreenHeight = ::GetSystemMetrics(SM_CYSCREEN)-1;
        double x, y;

        x = _dx *(65535.0f/fScreenWidth);
        y = _dy *(65535.0f/fScreenHeight);

        INPUT inp;
        inp.type = INPUT_MOUSE;
        inp.mi.dx = (int)x;
        inp.mi.dy = (int)y;
        inp.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
        inp.mi.time = 0;
        SendInput(1, &inp, sizeof(INPUT));
    }
}

void MouseDevice::leftHold(unsigned int modifier)
{
    if( attachedHwnd ) {
        LPARAM lparam = MAKELPARAM(vMouseX, vMouseY);
        PostMessage(attachedHwnd, WM_LBUTTONDOWN, MK_LBUTTON, lparam);
    } else {
        INPUT inp;
        memset(&inp, 0, sizeof(INPUT));
        inp.type = INPUT_MOUSE;
        inp.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
        SendInput(1, &inp, sizeof(INPUT));
    }
}

void MouseDevice::leftRelease(unsigned int modifier)
{
    if( attachedHwnd ) {
        LPARAM lparam = MAKELPARAM(vMouseX, vMouseY);
        PostMessage(attachedHwnd, WM_LBUTTONUP, MK_LBUTTON, lparam);
    } else {
        INPUT inp;
        memset(&inp, 0, sizeof(INPUT));
        inp.type = INPUT_MOUSE;
        inp.mi.dwFlags = MOUSEEVENTF_LEFTUP;
        SendInput(1, &inp, sizeof(INPUT));
    }
}

void MouseDevice::leftClick(unsigned int modifier)
{
    leftHold(modifier);
    Sleep(delay);
    leftRelease(modifier);
}

void MouseDevice::middleHold(unsigned int modifier)
{
    if( attachedHwnd ) {
        LPARAM lparam = MAKELPARAM(vMouseX, vMouseY);
        PostMessage(attachedHwnd, WM_MBUTTONDOWN, MK_MBUTTON, lparam);
    } else {
        INPUT inp;
        memset(&inp, 0, sizeof(INPUT));
        inp.type = INPUT_MOUSE;
        inp.mi.dwFlags = MOUSEEVENTF_MIDDLEDOWN;
        SendInput(1, &inp, sizeof(INPUT));
    }
}

void MouseDevice::middleRelease(unsigned int modifier)
{
    if( attachedHwnd ) {
        LPARAM lparam = MAKELPARAM(vMouseX, vMouseY);
        PostMessage(attachedHwnd, WM_MBUTTONUP, MK_MBUTTON, lparam);
    } else {
        INPUT inp;
        memset(&inp, 0, sizeof(INPUT));
        inp.type = INPUT_MOUSE;
        inp.mi.dwFlags = MOUSEEVENTF_MIDDLEUP;
        SendInput(1, &inp, sizeof(INPUT));
  }
}

void MouseDevice::middleClick(unsigned int modifier)
{
    middleHold(modifier);
    Sleep(delay);
    middleRelease(modifier);
}

void MouseDevice::rightHold(unsigned int modifier)
{
    if( attachedHwnd ) {
        LPARAM lparam = MAKELPARAM(vMouseX, vMouseY);
        PostMessage(attachedHwnd, WM_RBUTTONDOWN, MK_RBUTTON, lparam);
    } else {
        INPUT inp;
        memset(&inp, 0, sizeof(INPUT));
        inp.type = INPUT_MOUSE;
        inp.mi.dwFlags = MOUSEEVENTF_RIGHTDOWN;
        SendInput(1, &inp, sizeof(INPUT));
    }
}

void MouseDevice::rightRelease(unsigned int modifier)
{
    if( attachedHwnd ) {
        LPARAM lparam = MAKELPARAM(vMouseX, vMouseY);
        PostMessage(attachedHwnd, WM_RBUTTONUP, MK_RBUTTON, lparam);
    } else {
        INPUT inp;
        memset(&inp, 0, sizeof(INPUT));
        inp.type = INPUT_MOUSE;
        inp.mi.dwFlags = MOUSEEVENTF_RIGHTUP;
        SendInput(1, &inp, sizeof(INPUT));
    }
}

void MouseDevice::rightClick(unsigned int modifier)
{
    rightHold(modifier);
    Sleep(delay);
    rightRelease(modifier);
}

void MouseDevice::wheelMove(int delta)
{
    /* Delta of 120 means a click, so we can't have that */
    if( delta == 120 )
        delta = 119;

    if( attachedHwnd )
    {
        WPARAM wparam = MAKEWPARAM(0, delta);
        LPARAM lparam = MAKELPARAM(vMouseX, vMouseY);
        PostMessage(attachedHwnd, WM_MOUSEWHEEL , wparam, lparam);
    } else {
        /* Change 'mouseData' to 'dwData' if you get an error */
        INPUT inp;
        inp.type = INPUT_MOUSE;
        inp.mi.dwFlags = MOUSEEVENTF_WHEEL;
        inp.mi.mouseData = (DWORD)(delta);
        SendInput(1, &inp, sizeof(INPUT));
    }
}

int MouseDevice::getX()
{
    POINT p;
    GetCursorPos(&p);
    return p.x;
}

int MouseDevice::getY()
{
    POINT p;
    GetCursorPos(&p);
    return p.y;
}

void MouseDevice::setWineMode(bool enabled)
{
	wineMode = enabled;
}
